/***********************************************************************
 *
 *    sensitive detector for detector read-out of silicon strip detector
 *
 ***********************************************************************/

#include "SensitiveDetector.hh"

using namespace std;

SensitiveDetector::SensitiveDetector(G4String name, G4int i, Data* Data)
  :G4VSensitiveDetector(name), data(Data), HC(i)
{
  if(strlen(data->HCName[HC]) == 0)
    {
      data->HCName[HC] = name + "HitsCollection";
      if(data->VerboseLevel > 0)
	cout<<"SensitiveDetector::SensitiveDetector("<<name<<", "<<HC<<", data): HCName["<<HC<<"] is set: "<<data->HCName[HC]<<endl;
    }
  else
    {
      if(data->VerboseLevel > 0)
	cout<<"SensitiveDetector::SensitiveDetector("<<name<<", "<<HC<<", data): warning HCName["<<HC<<"] is already set: "<<data->HCName[HC]<<endl;
      exit(1);
    }

  collectionName.insert(data->HCName[HC]);
}

SensitiveDetector::~SensitiveDetector()
{;}

void SensitiveDetector::Initialize(G4HCofThisEvent* evnt)
{
  hitsCollection = new HitsCollection(SensitiveDetectorName, data->HCName[HC]);
  if(data->VerboseLevel > 2)  
    cout<<"hitsCollection("<<SensitiveDetectorName<<", "<<data->HCName[HC]<<") = "<<hitsCollection<<endl;
  static G4int HCID;
  if(data->VerboseLevel > 4)
    {
      cout<<"getting CollectionID("<<data->HCName[HC]<<")"<<endl;
    }
  HCID = G4SDManager::GetSDMpointer()->GetCollectionID(data->HCName[HC]);
      
  evnt->AddHitsCollection(HCID, hitsCollection);
  
  if(data->VerboseLevel > 2)
    cout<<"SensitiveDetector::Initialize done"<<endl;
}

G4bool SensitiveDetector::ProcessHits(G4Step* aStep, G4TouchableHistory*)
{
 if(data->VerboseLevel > 6)
    cout<<"SensitiveDetector::ProcessHits starting ..."<<endl;
  //cout << "-----------------------------------next hit----------------" << endl;//testingcdposition
  //SDManager
  G4SDManager* SDman = G4SDManager::GetSDMpointer();

  //set segment, annular and radial to default values
  G4int si_seg_id = -1;
  G4int annular_id = -1;
  G4int radial_id = -1;

  G4double edep = aStep->GetTotalEnergyDeposit();

  if(edep == 0. && data->VerboseLevel > 6)
    {
      cout<<"SensitiveDetector::ProcessHits: edep == 0\n";
      return false;
    }

  SiHit* newHit = new SiHit();

  newHit->SetTrackID(aStep->GetTrack()->GetTrackID());
  newHit->SetParentID(aStep->GetTrack()->GetParentID());
  newHit->SetEdep(edep);

  G4StepPoint* stepPoint;
  if(aStep->GetPostStepPoint()->GetProcessDefinedStep()->GetProcessName()=="Transportation")
    stepPoint = aStep->GetPreStepPoint();
  else
    stepPoint = aStep->GetPostStepPoint();

  G4ThreeVector position = stepPoint->GetPosition();
  
  newHit->SetPos(position);
  
  G4TouchableHandle theTouchable = stepPoint->GetTouchableHandle();

  G4ThreeVector det_position = theTouchable->GetHistory()->GetTopTransform().TransformPoint(position);

  newHit->SetPosInDet(det_position);

  //check which HitCollectionID this is
  int CollectionID = SDman->GetCollectionID(hitsCollection);
  if(data->NumberOfHC > 0)
    {
      CollectionID -= SDman->GetCollectionID(data->HCName[0]);
    }

  if(data->VerboseLevel > 6)
    cout<<"CollectionID = "<<CollectionID<<endl;

  //check if hit is after dead layer (forward AND backward CD AND CDE)

  G4bool forwardCD  = ((data->settings->SSDZPosition - data->settings->fSSDThickness[CollectionID%4] + data->settings->SSDDeadLayer) < position.z() && (data->ExperimentType != 1 && data->ExperimentType != 2 && data->ExperimentType != 3));

  G4bool forwardCDE = ((data->settings->CDEZPosition - data->settings->feSSDThickness[CollectionID%4] + data->settings->SSDDeadLayer) < position.z() && (data->ExperimentType != 1 && data->ExperimentType != 2 && data->ExperimentType != 3) && data->CDPad==1);

  G4bool backwardCD = (-(data->settings->SSDZPosition - data->settings->bSSDThickness[CollectionID%4]  + data->settings->SSDDeadLayer) > position.z() && (data->ExperimentType != 0 && data->ExperimentType != 2));

  G4bool backwardCDE = (-(data->settings->CDEZPosition - data->settings->beSSDThickness[CollectionID%4] + data->settings->SSDDeadLayer) > position.z() && (data->ExperimentType != 0 && data->ExperimentType != 2) && data->CDPad==1);

//	if (forwardCD) printf("ID FCD %d \n",CollectionID+SDman->GetCollectionID(data->HCName[0]));

  G4bool forwardBarrel = false, backwardBarrel = false;

  if(data->ExperimentType > 1){ //with barrel
    forwardBarrel = (data->settings->ForwardBarrelZ - data->settings->BarrelActWidth/2. < position.z() && position.z() < data->settings->ForwardBarrelZ + data->settings->BarrelActWidth/2.);
      backwardBarrel = (data->settings->BackwardBarrelZ - data->settings->BarrelActWidth/2. < position.z() && position.z() < data->settings->BackwardBarrelZ + data->settings->BarrelActWidth/2.);
  }

//	if (forwardBarrel) printf("ID Barrel %d \n",CollectionID+SDman->GetCollectionID(data->HCName[0]));

  if(forwardCD || backwardCD)
    {
      G4double rho = position.getRho();
      if(data->VerboseLevel > 6)
	{
	  cout<<"found hit with z = "<<position.z()<<", rho = "<<rho<<" and edep = "<<edep<<" ... "<<flush;
	}

      //check if the hit is in the active area
      if(data->settings->SSDActInnerRad <= rho && rho <= data->settings->SSDActOuterRad)
	{
	  rho -= data->settings->SSDActInnerRad;                    //now rho=0 -> hit at inner edge of active area

	  if(data->VerboseLevel > 6)
	    {
	      cout<<"in active area rho = "<<rho/mm<<" mm ("<<forwardCD<<", "<<backwardCD<<", "<<forwardCDE<<", "<<backwardCDE<<")"<<endl;
	    }

	  G4double phi = position.getPhi();
	  if (phi < 0) phi += 360*deg;
	  if (360*deg < phi) phi -= 360*deg;
	  //check which segment the hit is in and then set phi to a range from 0 to 81.6 deg in this segment
	  G4double tmp = (data->settings->SSDAngle-data->settings->SSDSegAngle)/2.; // ssdangle =82 ssdsegangle =81.6 tmp =0.2
	  //cout << "-------------------CD hit-------------------"<<endl;//testingcdposition
//	  cout << "geant phi\t" << phi/degree;//testingcdposition
	  if(data->settings->SSDRotation+90*deg-data->settings->SSDSegAngle/2. < phi && phi < data->settings->SSDRotation+90*deg+data->settings->SSDSegAngle/2.)    //changed numbering sector 1 (bottom)
	    {
			phi -= data->settings->SSDRotation+90*deg-data->settings->SSDSegAngle/2.;
	      si_seg_id = 0; //was 0
	    }
	  else if(data->settings->SSDRotation+180.*deg-data->settings->SSDSegAngle/2. < phi && phi < data->settings->SSDRotation+data->settings->SSDSegAngle/2.+180.*deg)    //changed numbering sector 1 (bottom)
	    {
			phi -= data->settings->SSDRotation+180*deg-data->settings->SSDSegAngle/2.;
	      si_seg_id = 1;//was 1
	    }
	  else if(data->settings->SSDRotation+270.*deg-data->settings->SSDSegAngle/2. < phi && phi < data->settings->SSDRotation+data->settings->SSDSegAngle/2.+270.*deg)    //changed numbering sector 1 (bottom)
	    {
			phi -= data->settings->SSDRotation+270*deg-data->settings->SSDSegAngle/2.;
	      si_seg_id = 2;//was 2
	    }
	  else if(data->settings->SSDRotation+360.*deg-data->settings->SSDSegAngle/2. < phi && phi < 360.*deg)    //changed numbering sector 1 (bottom)
	    {
				phi -= data->settings->SSDRotation+360*deg-data->settings->SSDSegAngle/2.;
	    		si_seg_id = 3;
		 }
	  else if(0*deg < phi && phi < data->settings->SSDRotation+data->settings->SSDSegAngle/2.)    //changed numbering sector 1 (bottom)
	    {
				phi -= data->settings->SSDRotation-data->settings->SSDSegAngle/2.;
	      	si_seg_id = 3; //was3
	    }
	  else
	    {
	      phi = -1;
	    }
	  //cout << "\tgeant det " << si_seg_id << endl;//testingcdposition
	  // cout << "\tdet phi\t" << phi/degree <<"\t" << si_seg_id ;
	  //if(phi==-1)
	  //  cout << "\t -1 !!\t" << phi;

	  if(phi != -1 && (phi < 0*degree || phi > 360*degree))
	    {
	      cout<<"Error in SensitiveDetector::ProcessHits: hit detected but phi is out of range ("<<phi/degree<<" degree)"<<endl;
	    }

	  if(phi >= 0*degree)    //if the hit was in one of the segments
	    {
	      //set annular strip
	      G4double rho_red = rho; 
	      		
	      while(rho_red >= data->settings->SSDAnnPitch)
		{
		  rho_red -= data->settings->SSDAnnPitch;
		}	      		
	      		
	      if(rho_red < data->settings->SSDAnnWidth) //Hit is in a strip, not between two strips
		{
		  annular_id = (G4int) (rho/data->settings->SSDAnnPitch);
		}
	      else
		{
		  phi = -1;
		  si_seg_id = -1;
		}

	      if(data->VerboseLevel > 6)
		{
		  cout<<"SensitiveDetector: rho = "<<rho/mm<<" mm, rho_red = "<<rho_red/mm<<" mm, width = "<<data->settings->SSDAnnWidth/mm<<" mm => annular_id = "<<annular_id<<", si_seg_id = "<<si_seg_id<<endl;
		}
	      
	      //set radial strip
	      radial_id = (G4int) ((phi/deg)/(data->settings->SSDRadPitch/deg));
	      if(radial_id == (G4int) ((data->settings->SSDSegAngle/deg)/(data->settings->SSDRadPitch/deg)))
		{
		  radial_id = (G4int) ((data->settings->SSDSegAngle/deg)/(data->settings->SSDRadPitch/deg)) - 1;
		  if(data->VerboseLevel > 6)
		    {
		      cout<<"Warning, changed radial_id from "<<(G4int) ((data->settings->SSDSegAngle/deg)/(data->settings->SSDRadPitch/deg))<<" to "<<(G4int) ((data->settings->SSDSegAngle/deg)/(data->settings->SSDRadPitch/deg)) - 1<<" (phi = "<<phi/deg<<" degree, SSDRadPitch = "<<data->settings->SSDRadPitch/deg<<" degree, phi/SSDRadPitch = "<<(phi/deg)/(data->settings->SSDRadPitch/deg)<<")"<<endl;
		    }
		}
	      if((radial_id < 0 || (G4int) ((data->settings->SSDSegAngle/deg)/(data->settings->SSDRadPitch/deg)) < radial_id) && phi != -1)
		{
		  cout<<"Warning, radial_id is out of range: radial_id = "<<radial_id<<", phi = "<<phi/deg<<" degree ("<<phi<<"), SSDRadPitch = "<<data->settings->SSDRadPitch/deg<<" degree"<<endl;
		}
	      if(data->VerboseLevel > 6)
		{
		  cout<<"SensitiveDetector: phi = "<<phi/deg<<" degree, pitch = "<<data->settings->SSDRadPitch/deg<<" degree => radial_id = "<<radial_id<<endl;
		}
	      //cout << "------------------ " << endl;
	      //cout << "real strip " << radial_id;
	      if(data->ExperimentType > 1){//trex strips 24 -> 16
		if(radial_id>=4&&radial_id<20){
		  radial_id = (radial_id-4)/2 +4;
		}
		else if(radial_id>19){
		  radial_id -= 8;
		}
	      }
	      else{//old coulex strips 24 -> 12
		radial_id/=2;
	      }
	      //cout << " mux strip " << radial_id << endl;
	      
	      //cout << "\tdet strip\t" << radial_id << endl;
	    }//if(phi >= 0)
	} //active area
      else if(data->VerboseLevel > 6)
	{
	  cout<<"not in active area (SSDActInnerRad = "<<data->settings->SSDActInnerRad/mm<<" mm, SSDActOuterRad = "<<data->settings->SSDActOuterRad/mm<<" mm)"<<endl;
	}
  }//if(forwardCD || backwardCD)
  else if(forwardCDE || backwardCDE)
    {
		G4double rho = position.getRho();
      if(data->VerboseLevel > 6)
	{
	  cout<<"found hit with z = "<<position.z()<<", rho = "<<rho<<" and edep = "<<edep<<" ... "<<flush;
	}

      //check if the hit is in the active area
      if(data->settings->SSDActInnerRad <= rho && rho <= data->settings->SSDPadActOuterRad)
	{
	  rho -= data->settings->SSDActInnerRad;                    //now rho=0 -> hit at inner edge of active area

	  if(data->VerboseLevel > 6)
	    {
	      cout<<"in active area rho = "<<rho/mm<<" mm ("<<forwardCD<<", "<<backwardCD<<", "<<forwardCDE<<", "<<backwardCDE<<")"<<endl;
	    }

	  G4double phi = position.getPhi();
	  if (phi < 0) phi += 360*deg;
	  if (360*deg < phi) phi -= 360*deg;
//	  cout << "phi2:" << phi << endl;
	  //check which segment the hit is in and then set phi to a range from 0 to 81.6 deg in this segment
	  G4double tmp = (data->settings->SSDAngle-data->settings->SSDSegAngle)/2.; // ssdangle =82 ssdsegangle =81.6 tmp =0.2
	  //cout << "-------------------CD hit-------------------"<<endl;//testingcdposition
//	  cout << "geant phi\t" << phi/degree;//testingcdposition
	  if(data->settings->SSDRotation+90*deg-data->settings->SSDSegAngle/2. < phi && phi < data->settings->SSDRotation+90*deg+data->settings->SSDSegAngle/2.)    //changed numbering sector 1 (bottom)
	    {
			phi -= data->settings->SSDRotation+90*deg-data->settings->SSDSegAngle/2.;
	      si_seg_id = 0; //was 0
	    }
	  else if(data->settings->SSDRotation+180.*deg-data->settings->SSDSegAngle/2. < phi && phi < data->settings->SSDRotation+data->settings->SSDSegAngle/2.+180.*deg)    //changed numbering sector 1 (bottom)
	    {
			phi -= data->settings->SSDRotation+180*deg-data->settings->SSDSegAngle/2.;
	      si_seg_id = 1;//was 1
	    }
	  else if(data->settings->SSDRotation+270.*deg-data->settings->SSDSegAngle/2. < phi && phi < data->settings->SSDRotation+data->settings->SSDSegAngle/2.+270.*deg)    //changed numbering sector 1 (bottom)
	    {
			phi -= data->settings->SSDRotation+270*deg-data->settings->SSDSegAngle/2.;
	      si_seg_id = 2;//was 2
	    }
	  else if(data->settings->SSDRotation+360.*deg-data->settings->SSDSegAngle/2. < phi && phi < 360.*deg)    //changed numbering sector 1 (bottom)
	    {
				phi -= data->settings->SSDRotation+360*deg-data->settings->SSDSegAngle/2.;
	    		si_seg_id = 3;
		 }
	  else if(0*deg < phi && phi < data->settings->SSDRotation+data->settings->SSDSegAngle/2.)    //changed numbering sector 1 (bottom)
	    {
				phi -= data->settings->SSDRotation-data->settings->SSDSegAngle/2.;
	      	si_seg_id = 3; //was3
	    }
	  else
	    {
	      phi = -1;
	    }

	  if(phi != -1 && (phi < 0*degree || phi > 360*degree))
	    {
	      cout<<"Error in SensitiveDetector::ProcessHits: hit detected but phi is out of range ("<<phi/degree<<" degree)"<<endl;
	    }

	  if(data->VerboseLevel > 6)
	    {
	      cout<<"Hit in CDE, segment "<<si_seg_id<<endl;
	    }
	} //active area
      else if(data->VerboseLevel > 6)
	{
	  cout<<"not in active area (SSDActInnerRad = "<<data->settings->SSDActInnerRad/mm<<" mm, SSDPadActOuterRad = "<<data->settings->SSDPadActOuterRad/mm<<" mm)"<<endl;
	}
    }//else if(CDE)
  else if(forwardBarrel || backwardBarrel){
	 if((-data->settings->BarrelActWidth/2. <= det_position.z() && det_position.z() <= data->settings->BarrelActWidth/2.) && (-data->settings->BarrelActLength/2. <= det_position.x() && det_position.x() <= data->settings->BarrelActLength/2.)){
      annular_id = (Int_t) ((det_position.z()+data->settings->BarrelActWidth/2.)/data->settings->BarrelStripPitch); //in this case annular_id = strip number
      /*
      if(forwardBarrel){//testingcdposition
	cout << "barrel x " << det_position.x() << " y " << det_position.y() <<  " phi " << position.phi()/degree << " strip " <<annular_id << endl;
      }
      */
    }
    if(backwardBarrel && annular_id >= 0){
      //strip 0 always closest to target, change numbering for backward
      //cout << "sim phi " << position.phi()/degree << endl; 
      annular_id = 15 - annular_id;
    }
      
  }//else if(barrel)
  else if(data->VerboseLevel > 6)
    {
      cout<<"hit in inactive area: ("<<position.x()<<", "<<position.y()<<", "<<position.z()<<")"<<endl;
      cout<<(data->settings->SSDZPosition + data->settings->SSDDeadLayer)<<" - "<<(data->settings->SSDZPosition + data->settings->fSSDThickness[CollectionID%4])<<", "<<-(data->settings->SSDZPosition + data->settings->SSDDeadLayer)<<" - "<<-(data->settings->SSDZPosition + data->settings->bSSDThickness[CollectionID%4])<<", "<<(data->settings->CDEZPosition + data->settings->feSSDThickness[CollectionID%4] + data->settings->SSDDeadLayer)<<", "<<-(data->settings->CDEZPosition + data->settings->beSSDThickness[CollectionID%4] + data->settings->SSDDeadLayer)<<endl;
      
      cout<<data->settings->ForwardBarrelZ - data->settings->BarrelActWidth/2.<<" - "<<data->settings->ForwardBarrelZ + data->settings->BarrelActWidth/2.<<", "<<data->settings->BackwardBarrelZ - data->settings->BarrelActWidth/2.<<" - "<<data->settings->BackwardBarrelZ + data->settings->BarrelActWidth/2.<<endl;
    }

  if(forwardCD || backwardCD)
    {
		newHit->SetSiSegmentID(si_seg_id);
      newHit->SetAnnularID(annular_id);
      newHit->SetRadialID(radial_id);
    }
  else if(forwardCDE || backwardCDE)
    {
      newHit->SetSiSegmentID(si_seg_id);
      newHit->SetAnnularID(-1);
      newHit->SetRadialID(-1);
    }
  else if(forwardBarrel || backwardBarrel)
    {
      newHit->SetSiSegmentID(-1);
      newHit->SetAnnularID(annular_id);
      newHit->SetRadialID(-1);
    }
  else
    {
      newHit->SetSiSegmentID(-1);
      newHit->SetAnnularID(-1);
      newHit->SetRadialID(-1);
    }

  newHit->SetTrack(aStep->GetTrack());

  newHit->SetStep(aStep->GetTrack()->GetCurrentStepNumber());
  
  if( aStep->GetTrack()->GetNextVolume() != 0 ) 
    { 
      newHit->SetVolume(aStep->GetTrack()->GetVolume()->GetName());
	 } 
  else 
    {
      newHit->SetVolume("OutOfWorld");
	 }

//	if (forwardBarrel) cout << annular_id << "	" <<  det_position.getX() << "	" << det_position.getY() << "	" << det_position.getZ() << endl;
  
  hitsCollection->insert(newHit);
  
  if(data->VerboseLevel > 6)
    cout<<"SensitiveDetector::ProcessHits done ("<<newHit->GetSiSegmentID()<<", "<<newHit->GetAnnularID()<<", "<<newHit->GetRadialID()<<", "<<newHit->GetEdep()<<")"<<endl;

  return true;
}

void SensitiveDetector::EndOfEvent(G4HCofThisEvent*)
{;}







